package com.example.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.common.api.ResultCode;
import com.example.common.api.ResultUtil;
import com.example.common.constant.SecurityConstants;
import com.example.common.filter.ReactiveRequestContextHolder;
import com.example.common.util.GsonUtil;
import com.example.user.mapper.AddressMapper;
import com.example.user.model.dto.AddressDTO;
import com.example.user.model.po.AddressPO;
import com.example.user.model.vo.AddressVO;
import com.example.user.service.IAddressService;
import com.google.gson.JsonObject;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
public class AddressService extends ServiceImpl<AddressMapper, AddressPO> implements IAddressService {

    @Resource
    private AddressMapper addressMapper;

    /**
     * 创建用户的地址
     * */
    public Mono<ResultUtil> createAddress(AddressVO addressVO){
        log.info("create address begin, params: {}", addressVO.toString());

        AddressPO addressPO = new AddressPO();
        BeanUtils.copyProperties(addressVO, addressPO);

        //创建地址，默认是正常的
        addressPO.setStatus(0);

        int row = addressMapper.insert(addressPO);

        if (row > 0){
            AddressDTO addressDTO = new AddressDTO();
            BeanUtils.copyProperties(addressPO, addressDTO);

            log.info("create address end, success");
            return Mono.just(ResultUtil.success(addressDTO));
        }

        log.error("create address fail");
        return Mono.just(ResultUtil.failed(ResultCode.CREATE_ADDRESS_ERROR));
    }

    @Override
    public ResultUtil updateAddress(AddressVO addressVO) {
        log.info("update address begin, params: {}", addressVO.toString());

        AddressPO addressPO = new AddressPO();
        BeanUtils.copyProperties(addressVO, addressPO);

        int row = addressMapper.updateById(addressPO);

        if (row > 0){
            Map<String, Object> map = new HashMap<>();
            map.put("result", true);
            map.put("message", "修改用户地址成功！");
            return ResultUtil.success(map);
        }
        return ResultUtil.failed(ResultCode.UPDATE_ADDRESS_ERROR);
    }

    @Override
    public ResultUtil deleteAddress(Long id) {
        log.info("delete address begin, id: {}", id);

        AddressPO addressPO = new AddressPO();
        addressPO.setId(id);
        addressPO.setStatus(1);

        int row = addressMapper.updateById(addressPO);

        if (row > 0){
            Map<String, Object> map = new HashMap<>();
            map.put("result", true);
            map.put("message", "删除地址成功");
            return ResultUtil.success(map);
        }
        return ResultUtil.failed("删除地址失败");
    }

    @Override
    public Mono<ResultUtil> getAddressByPage(int pageIndex, int pageSize) {
        log.info("get address by page begin, pageIndex: {}; pageSize: {}", pageIndex, pageSize);

        Mono<ServerHttpRequest> requestMono = ReactiveRequestContextHolder.getRequest();

        return requestMono.flatMap(request -> {
            String userInfo = request.getHeaders().getFirst(SecurityConstants.HEADER_USER_INFO);
            log.info("get address by page, user info : {}", userInfo);
            JsonObject jsonObject = GsonUtil.toJsonObject(userInfo);
            String userId = jsonObject.get("userId").getAsString();
            log.info("get address by page, user id : {}", userId);

            Page<AddressPO> page = new Page<>(pageIndex, pageSize);
            QueryWrapper<AddressPO> queryWrapperAddress = new QueryWrapper<>();
            Map<String, Object> mapAddress = new HashMap<>();
            mapAddress.put("user_id", userId);
            queryWrapperAddress.allEq(mapAddress);

            log.info("get address by page, start sql");

            IPage<AddressPO> iPage = addressMapper.selectPage(page, queryWrapperAddress);

            log.info("get address by page, end sql");

            IPage<AddressDTO> iPageDTO = iPage.convert(addressPO -> {
                AddressDTO addressDTO = new AddressDTO();
                BeanUtils.copyProperties(addressPO, addressDTO);
                return addressDTO;
            });

            log.info("get address by page end");
            return Mono.just(ResultUtil.success(iPageDTO));
        });

    }

    @Override
    public ResultUtil getAddressById(Long id) {
        AddressPO addressPO = addressMapper.selectById(id);
        AddressDTO addressDTO = new AddressDTO();
        BeanUtils.copyProperties(addressPO, addressDTO);
        return ResultUtil.success(addressDTO);
    }

    @Override
    public Mono<ResultUtil> getAddressByUserId() {
        log.info("get address by user id begin");
        Mono<ServerHttpRequest> requestMono = ReactiveRequestContextHolder.getRequest();

        return requestMono.flatMap(request -> {
            String userInfo = request.getHeaders().getFirst(SecurityConstants.HEADER_USER_INFO);
            log.info("get address by page, user info : {}", userInfo);
            JsonObject jsonObject = GsonUtil.toJsonObject(userInfo);
            String userId = jsonObject.get("userId").getAsString();
            log.info("get address by page, user id : {}", userId);

            QueryWrapper<AddressPO> queryWrapperAddress = new QueryWrapper<>();
            Map<String, Object> mapAddress = new HashMap<>();
            mapAddress.put("user_id", userId);
            mapAddress.put("default_address", 0);
            queryWrapperAddress.allEq(mapAddress);

            log.info("get address by page, start sql");

            AddressPO addressPO = addressMapper.selectOne(queryWrapperAddress);

            return Mono.just(ResultUtil.success(addressPO));
        });
    }
}
